package com.matt.service.impl;

import com.dotflat.check.repository.CheckInRulerRepository;
import com.dotflat.check.service.CCheckerService;
import com.dotflat.dashboard.vo.ChildrenClassCheckVO;
import com.dotflat.page.PaginateInMemory;
import com.dotflat.staffExtend.domain.StaffExtendCareer;
import com.google.common.collect.ImmutableMap;
import com.matt.commons.dto.sso.StaffDTO;
import com.matt.commons.exception.BusinessException;
import com.matt.commons.page.PagerQuery;
import com.matt.domain.*;
import com.matt.domain.record.CheckInRule;
import com.matt.domain.record.CheckRecord;
import com.matt.domain.rel.RelClassesChildren;
import com.matt.domain.rel.RelClassesDoctor;
import com.matt.domain.rel.RelClassesNurse;
import com.matt.domain.rel.RelClassesTeacher;
import com.matt.domain.teaching.TeachingPlan;
import com.matt.foundation.DO.ClassListDO;
import com.matt.foundation.DO.TeachAreaListDO;
import com.matt.foundation.DO.TeacherDO;
import com.matt.foundation.constant.ClassesConstant;
import com.matt.foundation.constant.PermissionConstant;
import com.matt.foundation.model.ErrorCode;
import com.matt.foundation.query.ClassesQuery;
import com.matt.foundation.utils.CollectionUtil;
import com.matt.foundation.utils.DateUtil;
import com.matt.foundation.utils.ModelUtil;
import com.matt.foundation.utils.annotation.OptsTrace;
import com.matt.foundation.vo.*;
import com.matt.foundation.vo.classes.ClassesVo;
import com.matt.repository.ChildrenRepository;
import com.matt.repository.ClassesRepository;
import com.matt.repository.TeachingAreaRepository;
import com.matt.repository.base.ClassNativeRepository;
import com.matt.repository.base.ClassesChildrenRepository;
import com.matt.repository.base.ClassesTeacherRepository;
import com.matt.repository.base.ClassesTeachingAreaRepository;
import com.matt.repository.record.CheckRecordRepository;
import com.matt.repository.rel.*;
import com.matt.repository.teaching.TeachingPlanRepository;
import com.matt.service.ClassesService;
import com.matt.service.StaffActionLogService;
import com.matt.service.remoteCall.SsoCallService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.assertj.core.util.BigDecimalComparator;
import org.assertj.core.util.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static com.matt.foundation.model.ErrorCode.AREA_CLASSES_DUPLICATE;

/**
 * *******************************
 * Created by Ron.
 * form com.matt
 * on 2017/7/6
 * *******************************
 */
@Service
@Slf4j
public class ClassesServiceImpl implements ClassesService {

    @Autowired
    private ClassesRepository classesRepository;

    @Autowired
    private ClassesChildrenRepository classesChildrenRepository;

    @Autowired
    private ClassesTeacherRepository classesTeacherRepository;

    @Autowired
    private ClassesTeachingAreaRepository classesTeachingAreaRepository;

    @Autowired
    private TeachingPlanRepository teachingPlanRepository;

    @Autowired
    private RelClassesChildrenRepository relClassesChildrenRepository;

    @Autowired
    private RelClassesTeachingAreaRepository relClassesTeachingAreaRepository;

    @Autowired
    private TeachingAreaRepository teachingAreaRepository;

    @Autowired
    private CheckRecordRepository checkRecordRepository;

    @Autowired
    private SsoCallService ssoCallService;

    @Autowired
    private RelClassesTeacherRepository relClassesTeacherRepository;

    @Autowired
    private RelClassesNurseRepository relClassesNurseRepository;

    @Autowired
    private RelClassesDoctorRepository relClassesDoctorRepository;

    @Autowired
    private ClassNativeRepository classNativeRepository;

    @Autowired
    private ChildrenRepository childrenRepository;

    @Autowired
    private StaffActionLogService staffActionLogService;

    @Autowired
    private CCheckerService cCheckerService;

    @Autowired
    private CheckInRulerRepository checkInRulerRepository;

    @Override
    public Page<WebClassesPageVo> getClassesByConditions(ClassesQuery query) {
        List<WebClassesPageVo> list = classesTeacherRepository.findClassesByCondition(null, query);
        Long count = classesTeacherRepository.countClassesByArea(query);
        return new PageImpl<WebClassesPageVo>(list, PageRequest.of(query.getPageNum(), query.getPageSize()), count);
    }

    @Override
    public List<Classes> getClassesByAreaAndCategroy(String areaId, Integer category) {
        return classesRepository.findByAreaIdAndCategoryAndDeleted(areaId, category, false);
    }

    @Override
    public List<Classes> getActiveClassesByArea(String areaId) {
        return classesRepository.findByAreaIdAndDeleted(areaId, false);
    }

    @Override
    public Page<WebClassesPageVo> getClassesByStaff(StaffDTO staff, String roleId, ClassesQuery classesQuery) {

        classesQuery.setStaffId(staff.getId());
        classesQuery.setAreaId(staff.getAreaId());
        classesQuery.setDate(DateUtil.millisToDateTime(DateUtil.startOfDayOfMilli(System.currentTimeMillis()), "yyyy-MM-dd"));

        Page<WebClassesPageVo> classesPage = getClassesByStaff(roleId, classesQuery);

        return classesPage;
    }

    @Override
    public Page<WebClassesPageVo> getClassesByStaff(String roleCode, ClassesQuery query) {
        query.setStatus(0);
        List<WebClassesPageVo> list = classesTeacherRepository.findClassesByCondition(roleCode, query);
        Long count = classesTeacherRepository.countClassesByStaff(roleCode, query);
        return new PageImpl<WebClassesPageVo>(list, PageRequest.of(query.getPageNum(), query.getPageSize()), count);
    }


    @Override
    public List<ClassListDO> getClassesByTeacher(String teacherId, String areaId) {
        List<ClassListDO> classesList = classesTeacherRepository.findClassesByTeacher(teacherId, areaId);
        return classesList;
    }

    @Override
    /**
     * FIXME : 这里要改成PositionCode
     */
    public List<ClassListDO> getClassesByStaffId(String roleCode, String staffId, String areaId){
        if(PermissionConstant.Role.DOCTOR.codeOf().equals(roleCode)){
            //儿保医生的列表查询
            return classesTeacherRepository.findClassesByDoctor(staffId, areaId);
        }else if(PermissionConstant.Role.GARDEN_LEADER.codeOf().equals(roleCode)){
            //园长
            return classesTeacherRepository.findClassesByAreaLeader(staffId, areaId);
        }else{
            //老师
            return classesTeacherRepository.findClassesByTeacher(staffId, areaId);
        }
    }

    @Override
    public Map getClassesById(String classesId) {
        Map map = new HashMap();
        Classes classes = classesRepository.getOne(classesId);
        List<TeacherDO> teacherObjects = classesTeacherRepository.findByClassesId(classesId);

        map.put("class", classes);
        map.put("teacherList", teacherObjects);
        return map;
    }

    @Override
    public Classes getClassesById(String areaId, String classesId){
        Classes classes = classesRepository.findFirstByAreaIdAndIdAndDeletedIsFalse(areaId, classesId);

        return classes;
    }


    private List<ClassesChildrenListVo> childrenListWithCheckStatus(List<Object[]> objects){
        List<ClassesChildrenListVo> childrenList = objects.stream().map(o -> ClassesChildrenListVo.of(o)).collect(Collectors.toList());

        if(childrenList == null || childrenList.size() == 0){
            return new ArrayList<>();
        }

        List<String> childrenIds = childrenList.stream().map(k->k.getId()).collect(Collectors.toList());

        Date baseTime = new Date(DateUtil.startOfDayOfMilli(System.currentTimeMillis()));
        List<CheckRecord> checkRecordList = checkRecordRepository.findByChildrenIdInAndCheckInTimeGreaterThan(childrenIds, baseTime);

        Map<String, List<CheckRecord>> cache = new HashMap<>();
        for (CheckRecord c : checkRecordList){
            List<CheckRecord> records = cache.get(c.getChildrenId());
            if(records == null){
                records = new ArrayList<>();
                cache.put(c.getChildrenId(), records);
            }
            records.add(c);
        }

        childrenList.forEach(o -> {
            List<CheckRecord> records = cache.get(o.getId());
            if (records == null || records.size() == 0) {
                o.setCheckStatus("0");
            } else if (records.get(0).getCheckOutTime() == null) {
                o.setCheckStatus("1");
            } else {
                o.setCheckStatus("2");
            }
        });

        return childrenList;
    }

    @Override
    public Map getMemberByClassesId(String classId) {
        List<Object[]> objects = classesChildrenRepository.findChildrenByClassesAndNurseryStatus(classId);
        List<ClassesChildrenListVo> childrenList = childrenListWithCheckStatus(objects);
        List<TeacherDO> teacherObjects = classesTeacherRepository.findByClassesId(classId);
        List<TeachAreaListDO> roomList = classesTeachingAreaRepository.findByClassesId(classId);
        return ImmutableMap.of("childrenList", childrenList, "teacherList", teacherObjects, "teachingAreaList", roomList);
    }

//    @Override
//    public Map getPadMemberByClassesId(String classId) {
//        List<Object[]> objects = classesChildrenRepository.findChildrenByClasses(classId);
//        List<ClassesChildrenListVo> childrenList = childrenListWithCheckStatus(objects);
//
//        List<TeacherDO> teacherObjects = classesTeacherRepository.findTeacherIdByClassesId(classId);
//
//        List<Object[]> roomsObjects = classesTeachingAreaRepository.findRoomsByClassesId(classId);
//        List<RoomListVo> roomList = roomsObjects.stream().map(o -> RoomListVo.of(o)).collect(Collectors.toList());
//        return ImmutableMap.of("childrenList", childrenList, "teacherList", teacherObjects, "roomList", roomList);
//    }

//    @Override
//    public List<Children> getChildrenByClassesId(String areaId, String classId){
//        return childrenRepository.findAllChildrenByAreaIdAndClassId(areaId, classId);
//    }
    @Override
    public Page<Children> getChildIdsByClassesId(String areaId, String classId, PagerQuery pagerQuery){

        Pageable pageable = PageRequest.of(pagerQuery.getPageNum(), pagerQuery.getPageSize());

        Page<Children> childrenList = childrenRepository.findAllChildrenByAreaIdAndClassId(areaId, classId, pageable);

        return childrenList;
    }

    @Override
    public Children getAnyMemberByClassesIdAndName(String areaId, String classId, String name){
        Classes c = getClassesById(areaId, classId);

        Children ret = classesChildrenRepository.findAnyChildrenByClassesAndName(c.getId(), name);

        return ret;
    }


    @Override
    public Map getPlanByClasses(String classesId, String date, String ticket, String staffId) {
/*        Classes classes = classesRepository.getOne(classesId);


        if (Objects.isNull(classes))
            throw new BusinessException(ErrorCode.CLASSES_NOT_EXIST, "班级不存在！");

        if (Objects.isNull(classes.getBaseTime()))
            throw new BusinessException(ErrorCode.CLASSES_BASE_TIME_IS_NULL, "园长还未对该班级进行排课");

        Date today = DateUtil.parseToDate(date);
        Date baseDay = classes.getBaseTime();
        Long days = DateUtil.betweenDays(baseDay, today);
        List<TeachingPlan> teachingPlans = teachingPlanRepository.findByMonthAndDayAndIsDeletedOrderByFromTime(ModelUtil.getMonth(days), ModelUtil.getDay(days), false);
        List<PlanListVo> planList = teachingPlans.stream().map(o -> PlanListVo.of(o, SERVER_WEBSITE_IP, ticket)).collect(Collectors.toList());
        List<GardenAdviseVo> advises = gardenAdviseChildrenRepository.findChildrenByClasses(classesId).stream().map(o -> GardenAdviseVo.of(o)).collect(Collectors.toList());*/
//        PrepareLessonRecordNursery prepareLessonRecord = prepareLessonRecordRepository.findByClassesIdAndTeacherIdAndPrepareDate(classesId, staffId, today);
        Map map = new HashMap();
     /*   map.put("days", days);
        map.put("teachingPlans", planList);
        map.put("advises", advises);*/
        map.put("prepareLessonRecord", null);
        return map;
    }

    @Override
    public Map getPlanByDay(Long day, String ticket) {
       List<TeachingPlan> teachingPlans = teachingPlanRepository.findByMonthAndDayAndIsDeletedOrderByFromTime(ModelUtil.getMonth(day), ModelUtil.getDay(day), false);
        List<PlanListVo> planList = teachingPlans.stream().map(o -> PlanListVo.of(o, "", ticket)).collect(Collectors.toList());
        return ImmutableMap.of("days", day, "teachingPlans", planList);

    }

    @OptsTrace(code = "0400")
    @Override
    @Transactional
    public Classes createClasses(String classId, String name, String areaId, String[] childrenIds, String[] teacherIds,
                                 String[] nurseIds,String[] doctorIds, String[] teachingAreaIds, String remark, Integer limitNum,
                                 String targetObjectId, StaffDTO inChargeTeacher, Integer category, Integer beginMonth, Integer endMonth) {
        Classes classes = null;
        if (StringUtils.isNotBlank(classId)) { //新增班级
            classes = classesRepository.getOne(classId);
            if (!classes.getAreaId().equals(areaId)){
                throw new BusinessException(ErrorCode.CLASSES_NOT_EXIST, "班级不存在");
            }
        }
        Classes nameChecker = classesRepository.findByNameAndAreaId(name, areaId);
        if (classes == null && nameChecker != null){
            throw new BusinessException(AREA_CLASSES_DUPLICATE, "班级名称重复");
        }
        if (nameChecker != null && classes != null && nameChecker.getId().equals(classes.getName())){
            throw new BusinessException(AREA_CLASSES_DUPLICATE, "班级名称重复");
        }

        if (childrenIds.length > limitNum)
            throw new BusinessException(ErrorCode.CLASSES_MEMBERS_MORE_THAN_LIMIT, "班级学生数超过限制");

        if (classes == null){
            classes = new Classes();
        }else{
            //重置下各种关系
            relClassesChildrenRepository.deleteByClassesId(classes.getId());
            relClassesTeachingAreaRepository.deleteByClassesId(classes.getId());
            relClassesTeacherRepository.deleteByClassesId(classes.getId());
            relClassesNurseRepository.deleteAllByIdLinkId(classes.getId());
            relClassesDoctorRepository.deleteAllByIdLinkId(classes.getId());
        }

        Date today = new Date();
        classes.setName(name);
        classes.setAreaId(areaId);
        classes.setCreated(today);
        classes.setRemark(remark);
        classes.setLimitNum(limitNum);
        classes.setTargetObjectId(targetObjectId);
        classes.setCategory(category);
        classes.setBeginMonth(beginMonth);
        classes.setEndMonth(endMonth);
        classes.setInChargeTeacherId(inChargeTeacher.getId());
        classes.setInChargeTeacherName(inChargeTeacher.getRealName());

        classesRepository.save(classes);
        insertChildren(childrenIds, classes);

        List<String> teacherList = Lists.newArrayList(teacherIds);
        teacherList.add(inChargeTeacher.getId());

        insertTeachers(teacherList.toArray(new String[teacherList.size()]), classes);
        insertTeachingAreas(teachingAreaIds, classes);
        if (nurseIds != null) {
            insertNurses(nurseIds, classes);
        }
        //新增医生
        if (doctorIds != null) {
            insertDoctors(doctorIds, classes);
        }

        //为班级创建主题
        if (classes.getCategory() == ClassesConstant.Category.NURSERY.codeOf()) {
            //FIXME 有问题
            // 已经不需要给班级排默认主题课程了
            // courseTopicService.cleanClassesTopicCourse(classes, null, targetObjectId);
        }

        return classes;
    }

    @OptsTrace(code = "0401")
    @Override
    @Transactional
    public Classes modifyClasses(String classesId, String name, String areaId, String[] childrenIds, String[] teacherIds,
                                 String[] nurseIds, String[] cameraIds, String remark, Integer limitNum, String targetObjectId,
                                 StaffDTO inChargeTeacher, Integer category, Integer beginMonth, Integer endMonth) {

        Classes classes = classesRepository.findByNameAndAreaId(name, areaId);
        if (Objects.nonNull(classes) && !classes.getId().equals(classesId))
            throw new BusinessException(AREA_CLASSES_DUPLICATE, "班级名称重复");

        classes = classesRepository.getOne(classesId);
        if (Objects.isNull(classes))
            throw new BusinessException(ErrorCode.CLASSES_NOT_EXIST, "班级不存在");

        if (childrenIds.length > limitNum)
            throw new BusinessException(ErrorCode.CLASSES_MEMBERS_MORE_THAN_LIMIT, "班级学生数超过限制");


        //重新安排课程
        if (category == ClassesConstant.Category.NURSERY.codeOf() && !targetObjectId.equals(classes.getTargetObjectId())) {

            //TODO 由于目前业务排课基本是全部类型，所以目前处理是班级类型改变，课程暂时不做任何变化，后期随业务再进行调整
//            throw new BusinessException(ErrorCode.TARGET_CAN_NOT_CHANGE, "适用对象暂时不允许修改");
//            courseTopicService.cleanClassesTopicCourse(classes, classes.getTargetObjectId(), targetObjectId);
        }
        if (teacherIds != null) {
            List<RelClassesTeacher> classesTeachers =  relClassesTeacherRepository.findByClassesId(classesId);
            List<String> stringList = classesTeachers.stream().map(k->k.getStaffId()).collect(Collectors.toList());
            String[]  teacherIds1 =  compare2(teacherIds, stringList.toArray(new String[stringList.size()]));
            List<StaffExtendCareer> logList = new ArrayList<>();
            for (int i = 0; i < teacherIds1.length; i++) {
                boolean contains = Arrays.asList(teacherIds1).contains(teacherIds1[i]);
                if (contains){
                    logList.add(StaffExtendCareer.of(areaId,"",teacherIds1[i],name+"班主任任职"));
                }else {
                    logList.add(StaffExtendCareer.of(areaId,"",teacherIds1[i],name+"班主任离职"));
                }
            }
            staffActionLogService.saveList(logList);
        }
        if (cameraIds != null) {
            List<RelClassesTeachingArea>  relClassesTeachingAreas =  relClassesTeachingAreaRepository.findByClassesId(classesId);
            List<String> stringList = relClassesTeachingAreas.stream().map(k->k.getTeachingAreaId()).collect(Collectors.toList());
            String[]  teacherIds1 =  compare2(cameraIds, stringList.toArray(new String[stringList.size()]));
            List<StaffExtendCareer> logList = new ArrayList<>();
            for (int i = 0; i < teacherIds1.length; i++) {
                boolean contains = Arrays.asList(teacherIds1).contains(teacherIds1[i]);
                if (contains){
                    logList.add(StaffExtendCareer.of(areaId,"",teacherIds1[i],name+"老师任职"));
                }else {
                    logList.add(StaffExtendCareer.of(areaId,"",teacherIds1[i],name+"老师离职"));
                }
            }
            staffActionLogService.saveList(logList);
        }
        if (nurseIds != null) {
            List<RelClassesNurse>  relClassesNurses = relClassesNurseRepository.findByIdLinkId(classesId);
            List<String> stringList = relClassesNurses.stream().map(k->k.getId().getDomainId()).collect(Collectors.toList());
            String[]  teacherIds1 =  compare2(nurseIds, stringList.toArray(new String[stringList.size()]));
            List<StaffExtendCareer> logList = new ArrayList<>();
            for (int i = 0; i < teacherIds1.length; i++) {
                boolean contains = Arrays.asList(teacherIds1).contains(teacherIds1[i]);
                if (contains){
                    logList.add(StaffExtendCareer.of(areaId,"",teacherIds1[i],name+"儿保医生任职"));
                }else {
                    logList.add(StaffExtendCareer.of(areaId,"",teacherIds1[i],name+"儿保医生离职"));
                }
            }
            staffActionLogService.saveList(logList);
        }

        classes.setName(name);
        classes.setRemark(remark);
        classes.setLimitNum(limitNum);
        classes.setTargetObjectId(targetObjectId);
        classes.setInChargeTeacherId(inChargeTeacher.getId());
        classes.setInChargeTeacherName(inChargeTeacher.getRealName());
        classes.setCategory(category);
        classes.setBeginMonth(beginMonth);
        classes.setEndMonth(endMonth);
        classesRepository.save(classes);
        relClassesChildrenRepository.deleteByClassesId(classesId);
        relClassesTeachingAreaRepository.deleteByClassesId(classesId);
        relClassesTeacherRepository.deleteByClassesId(classesId);
        relClassesNurseRepository.deleteAllByIdLinkId(classesId);
        relClassesDoctorRepository.deleteAllByIdLinkId(classesId);

        insertChildren(childrenIds, classes);

        List<String> teacherList = Lists.newArrayList(teacherIds);
        teacherList.add(inChargeTeacher.getId());
        removeDuplicate(teacherList);

        insertTeachers(teacherList.toArray(new String[teacherList.size()]), classes);
        insertTeachingAreas(cameraIds, classes);
        if (nurseIds != null) {
            insertNurses(nurseIds, classes);
        }
        return classes;
    }
    //查询二个集合中不相同的数据
    public static String[] compare2(String[] arr1, String[] arr2) {
        Set<String> set1 = new HashSet<>(Arrays.asList(arr1));
        Set<String> set2 = new HashSet<>(Arrays.asList(arr2));
        Set<String> set3 = new HashSet<>(set2);

        set3.addAll(set1);//set3 [100, 1, 2, 5, 7, -1]; set集合有去重特性
        set1.retainAll(set2);//retainAll():保留包含在指定 collection 中的元素；s1：[-1,1,2]
        set3.removeAll(set1);//	removeAll(); 移除 set 中那些包含在指定 collection 中的元素 ; s3 [3,4,100,5,7,-12,12]
        return set3.toArray(new String[set3.size()]);
    }
    //去重复
    public  List removeDuplicate(List list) {
        HashSet h = new HashSet(list);
        list.clear();
        list.addAll(h);
        return list;
    }

    private void insertChildren(String[] childrenIds, Classes classes) {
        List<RelClassesChildren> childrenList = new ArrayList<>();
        for (int i = 0; i < childrenIds.length; i++) {
            RelClassesChildren classesChildren = new RelClassesChildren();
            classesChildren.setChildrenId(childrenIds[i]);
            classesChildren.setClassesId(classes.getId());
            childrenList.add(classesChildren);
        }
        relClassesChildrenRepository.saveAll(childrenList);
    }

    private void insertTeachers(String[] teacherIds, Classes classes) {
        List<RelClassesTeacher> teacherList = new ArrayList<>();
        for (int i = 0; i < teacherIds.length; i++) {
            RelClassesTeacher classesTeacher = new RelClassesTeacher();
            classesTeacher.setStaffId(teacherIds[i]);
            classesTeacher.setClassesId(classes.getId());
            teacherList.add(classesTeacher);
        }
        relClassesTeacherRepository.saveAll(teacherList);
    }

    //增加班级-保育员关系
    private void insertNurses(String[] ids, Classes classes) {
        List<RelClassesNurse> nurseList = new ArrayList<>();
        for (String id : ids) {
            if (StringUtils.isNotBlank(id)) {
                nurseList.add(RelClassesNurse.of(id, classes.getId()));
            }
        }
        relClassesNurseRepository.saveAll(nurseList);
    }

    //增加班级-医生关系
    private void insertDoctors(String[] ids, Classes classes) {
        List<RelClassesDoctor> doctorList = new ArrayList<>();
        for (String id : ids) {
            if (StringUtils.isNotBlank(id)) {
            	doctorList.add(RelClassesDoctor.of(id, classes.getId()));
            }
        }
        relClassesDoctorRepository.saveAll(doctorList);
    }

    private void insertTeachingAreas(String[] teachingAreaIds, Classes classes) {
        List<RelClassesTeachingArea> roomList = new ArrayList<>();
        for (int i = 0; i < teachingAreaIds.length; i++) {

            TeachingArea a = teachingAreaRepository.getOne(teachingAreaIds[i]);
            if(a == null || !classes.getAreaId().equals(a.getAreaId())){
                throw new BusinessException(ErrorCode.AREA_TEACHING_AREA_NOT_EXIST, "教学区域不存在");
            }

            if(a.getIsPublic()){
                throw new BusinessException(ErrorCode.AREA_TEACHING_AREA_NOT_VALID, "不能配置公共区域");
            }

            RelClassesTeachingArea classesTeachingArea = new RelClassesTeachingArea();
            classesTeachingArea.setTeachingAreaId(teachingAreaIds[i]);
            classesTeachingArea.setClassesId(classes.getId());
            roomList.add(classesTeachingArea);
        }
        relClassesTeachingAreaRepository.saveAll(roomList);
    }

    @Override
    public Map getDetailByClassesId(String classId) {
        Map result = new HashMap<>();
        Classes classes = classesRepository.getOne(classId);
        if (Objects.isNull(classes))
            throw new BusinessException(ErrorCode.CLASSES_NOT_EXIST, "班级不存在");

        String createClassStaffId = classes.getInChargeTeacherId();
        StaffDTO createClassesStaff = null;
        if (StringUtils.isNotEmpty(createClassStaffId)){
            createClassesStaff = ssoCallService.getStaffDTO(null, createClassStaffId);
        }

        List<Object[]> objects = classesChildrenRepository.findChildrenByClasses(classId);
        List<ClassesChildrenListVo> childrenList = objects.stream().map(o -> ClassesChildrenListVo.of(o)).collect(Collectors.toList());
        List<TeacherDO> teacherObjects = classesTeacherRepository.findByClassesId(classId);

        List<TeacherVo> teacherVoList = teacherObjects.stream().map(o -> TeacherVo.of(o)).filter(o -> !o.getId().equals(classes.getInChargeTeacherId())).collect(Collectors.toList());
        List<TeachAreaListDO> roomList = classesTeachingAreaRepository.findByClassesId(classId);

        //根据classId查询保育员
        List<RelClassesNurse> nurseList = relClassesNurseRepository.findAll((root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(cb.equal(root.get("id").get("linkId").as(String.class), classId));
            return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
        });
        String[] nurseIds=CollectionUtil.toArray(nurseList.stream().map(o -> o.getId().getDomainId()).collect(Collectors.toList()));
        List<StaffDTO> staffDTOList=ssoCallService.getStaffDTOList(null, nurseIds);
        List<NurseVo> nurseVoList = staffDTOList.stream().map(o -> NurseVo.of(o)).collect(Collectors.toList());

        //根据classId查询保育员
        List<RelClassesDoctor> doctorList = relClassesDoctorRepository.findAll((root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(cb.equal(root.get("id").get("linkId").as(String.class), classId));
            return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
        });
        String[] doctorIds=CollectionUtil.toArray(doctorList.stream().map(o -> o.getId().getDomainId()).collect(Collectors.toList()));
        List<StaffDTO> doctorDTOList=ssoCallService.getStaffDTOList(null, doctorIds);
        List<DoctorVo> doctorVoList = doctorDTOList.stream().map(o -> DoctorVo.of(o)).collect(Collectors.toList());

        result.put("childrenList",childrenList);
        result.put("teacherList",teacherVoList);
        result.put("teachingAreaList",roomList);
        result.put("classes",classes);
        result.put("nurseList",nurseVoList);
        result.put("doctorList",doctorVoList);
        if(createClassesStaff!=null) {
            result.put("createClassesStaff", createClassesStaff);
        }
       return result ;
    }


    @Override
    public List getDetailByClassesIdList(TeacherDO teacherDO) {
        Map result = new HashMap<>();
        Classes classes = classesRepository.getOne(teacherDO.getId());
        if (Objects.isNull(classes))
            throw new BusinessException(ErrorCode.CLASSES_NOT_EXIST, "班级不存在");

        String createClassStaffId = classes.getInChargeTeacherId();
        StaffDTO createClassesStaff = null;
        if (StringUtils.isNotEmpty(createClassStaffId)){
            createClassesStaff = ssoCallService.getStaffDTO(null, createClassStaffId);
        }

        List<Object[]> objects = classesChildrenRepository.findChildrenByClasses(teacherDO.getId());
        List<ClassesChildrenListVo> childrenList = objects.stream().map(o -> ClassesChildrenListVo.of(o)).collect(Collectors.toList());
        List<TeacherDO> teacherObjects = classesTeacherRepository.findByClassesId(teacherDO.getId());

//        List<TeacherDO> teacherByClassId = classesTeachingAreaRepository.findTeacherByClassId(teacherDO.getId());


        List<TeacherDO> teacherDOList = ssoCallService.getTeacherByClassId(teacherDO.getId());
        teacherDOList.addAll(teacherObjects);


//        List<TeacherVo> teacherVoList = teacherObjects.stream().map(o -> TeacherVo.of(o)).filter(o -> !o.getId().equals(classes.getInChargeTeacherId())).collect(Collectors.toList());
        List<TeachAreaListDO> roomList = classesTeachingAreaRepository.findByClassesId(teacherDO.getId());

        //根据classId查询保育员
        List<RelClassesNurse> nurseList = relClassesNurseRepository.findAll((root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(cb.equal(root.get("id").get("linkId").as(String.class), teacherDO.getId()));
            return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
        });
        String[] nurseIds=CollectionUtil.toArray(nurseList.stream().map(o -> o.getId().getDomainId()).collect(Collectors.toList()));
        List<StaffDTO> staffDTOList=ssoCallService.getStaffDTOList(null, nurseIds);
        List<NurseVo> nurseVoList = staffDTOList.stream().map(o -> NurseVo.of(o)).collect(Collectors.toList());

        //根据classId查询保育员
        List<RelClassesDoctor> doctorList = relClassesDoctorRepository.findAll((root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(cb.equal(root.get("id").get("linkId").as(String.class), teacherDO.getId()));
            return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
        });
        String[] doctorIds=CollectionUtil.toArray(doctorList.stream().map(o -> o.getId().getDomainId()).collect(Collectors.toList()));
        List<StaffDTO> doctorDTOList=ssoCallService.getStaffDTOList(null, doctorIds);
        List<DoctorVo> doctorVoList = doctorDTOList.stream().map(o -> DoctorVo.of(o)).collect(Collectors.toList());

        result.put("childrenList",childrenList);
        result.put("teacherList",teacherDOList);
        result.put("teachingAreaList",roomList);
        result.put("classes",classes);
        result.put("nurseList",nurseVoList);
        result.put("doctorList",doctorVoList);
        if(createClassesStaff!=null) {
            result.put("createClassesStaff", createClassesStaff);
        }
        return teacherDOList ;
    }

    @Transactional
    @Override
    public Boolean disable(String classesId) {
        Classes classes = classesRepository.getOne(classesId);
        classes.setDeleted(true);
//        classes.setInChargeTeacherId(null);
//        classes.setInChargeTeacherName(null);
        classesRepository.save(classes);
        //移除班级所有学生和老师
//        relClassesChildrenRepository.deleteByClassesId(classesId);
//        relClassesTeacherRepository.deleteByClassesId(classesId);
        return true;
    }

    @Transactional
    @Override
    public Boolean enable(String classId) {
        Classes classes = classesRepository.getOne(classId);
        classes.setDeleted(false);
        classesRepository.save(classes);
        return true;
    }

    @OptsTrace(code = "0402")
    @Override
    @Transactional
    public Classes scheduled(String classesId, String baseTime) {
        Classes classes = classesRepository.getOne(classesId);
        classes.setBaseTime(DateUtil.parseToDate(baseTime));
        classesRepository.save(classes);
        return classes;
    }

    @Override
    public List<ClassesVo> getClassesByAreaAndCategory(String areaId, Integer category) {
        return classNativeRepository.findByAreaIdAndCategoryAndDeleted(areaId, category);
    }

    @Override
    public List<ClassesVo> getClassesByArea(String areaId) {
        return classNativeRepository.findByAreaId(areaId);
    }

    @Override
    public List<Classes> getNurseryClassesListByTargetObject(String allTargetObjectId, String targetObjectId) {
        if (allTargetObjectId.equals(targetObjectId))
            return classesRepository.findByCategoryAndDeleted(ClassesConstant.Category.NURSERY.codeOf(), false);
        else
            return classesRepository.findByCategoryAndTargetObjectIdAndDeleted(ClassesConstant.Category.NURSERY.codeOf(), targetObjectId, false);
    }

    @Override
    public Integer getAreaNurseryClassesCount(String areaId, String date, boolean deleted) {
        Long count = classesRepository.countByAreaIdAndCategoryAndDeleted(areaId,ClassesConstant.Category.NURSERY.codeOf(),deleted);
        if (count !=null)
            return count.intValue();
        return 0;
    }

    @Override
    public Integer getTeacherChildCheckInCount(String staffId, String date) {
        return classNativeRepository.getTeacherChildCheckInCount(staffId,date);
    }

    @Override
    public Classes selectClassById(String classesId) {
        Classes classes = classesRepository.findFirstById(classesId);
        return classes;
    }

    /**
     * 考勤列表
     * @param query
     * @return
     */
    @Override
    public Page<ChildrenClassCheckVO> getClassCheckList(ClassesQuery query) {
        List<ChildrenClassCheckVO> checkVOList = new ArrayList<>();

        Page<WebClassesPageVo> classesByConditions = this.getClassesByConditions(query);
        for (WebClassesPageVo webClassesPageVo : classesByConditions.getContent()) {
            ChildrenClassCheckVO childrenClassCheckVO = new ChildrenClassCheckVO();
            childrenClassCheckVO.setClassesName(webClassesPageVo.getName());//班级名称
            childrenClassCheckVO.setClassesId(webClassesPageVo.getId());//班级id
            //查询班级人数
            Integer classNum = Optional.ofNullable(Math.toIntExact(relClassesChildrenRepository.countByClassesIdAndStatus(webClassesPageVo.getId(),1))).orElse(0);
            childrenClassCheckVO.setClassesTotal(classNum);
            //查询班级考勤人数
            Integer checkNum = checkRecordRepository.findRecordCountByClassId(query.getTodayDate(), webClassesPageVo.getId());
            if(null==checkNum){
                checkNum=0;
            }
            childrenClassCheckVO.setActualArrivalTotal(checkNum);
            if(classNum==0 || checkNum==0){
                childrenClassCheckVO.setAttendanceRate("0");
            }else{
                //计算出勤率
                BigDecimal attendanceRate = new BigDecimal(checkNum).divide(new BigDecimal(classNum), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
                childrenClassCheckVO.setAttendanceRate(attendanceRate+"%");
            }

            checkVOList.add(childrenClassCheckVO);

        }

        return new PageImpl<>(checkVOList, PageRequest.of(query.getPageNum(), query.getPageSize()),classesByConditions.getTotalElements());

    }

    /**
     * 考勤详情
     * @param query
     * @return
     */
    @Override
    public Page<ChildrenClassCheckVO> getClassCheckDetail(ClassesQuery query) {
        List<Object[]> classCheckDetailList = classesRepository.getClassCheckDetail(query.getId(), query.getTodayDate());

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 将 Object[] 映射到 ChildrenClassCheckVO
        Map<String, List<ChildrenClassCheckVO>> groupMap = classCheckDetailList.stream()
                .map(row -> {
                    ChildrenClassCheckVO vo = new ChildrenClassCheckVO();
                    vo.setClassesName(null != row[0] ? row[0].toString() : null);
                    vo.setChildrenName(null != row[1] ? row[1].toString() : null);
                    vo.setStatus(null != row[2] ? (Integer) row[2] : null);
                    vo.setCheckInTime(null != row[3] ? simpleDateFormat.format(row[3]) : null);
                    vo.setCheckOutTime(null != row[4] ? simpleDateFormat.format(row[4]) : null);
                    vo.setChildrenId(null != row[5] ? row[5].toString() : null); // 设置childrenId
                    vo.setTemperature(null != row[6] ? row[6].toString() : null); // temperature
                    vo.setTemperature1(null != row[7] ? row[7].toString() : null); // temperature1
                    return vo;
                })
                .collect(Collectors.groupingBy(ChildrenClassCheckVO::getChildrenId));
        if(null==groupMap || groupMap.isEmpty()){
            return new PageImpl<>(new ArrayList<>(), PageRequest.of(query.getPageNum(), query.getPageSize()),0);
        }

        List<ChildrenClassCheckVO> newList = new ArrayList<>();
        groupMap.entrySet().forEach(entry -> {
            if(entry.getValue().size()>1){
                //入园和出园是两条数据，只有入园时间和离园时间不同 （合并两条数据）
                ChildrenClassCheckVO childrenClassCheckVO = new ChildrenClassCheckVO();
                BeanUtils.copyProperties(entry.getValue().get(0), childrenClassCheckVO);
                if(null==childrenClassCheckVO.getCheckOutTime() && null!=entry.getValue().get(1).getCheckOutTime()){
                    childrenClassCheckVO.setCheckOutTime(entry.getValue().get(1).getCheckOutTime());
                }
                if(null!=entry.getValue().get(0).getTemperature()){
                    childrenClassCheckVO.setTemperature(entry.getValue().get(0).getTemperature());
                    childrenClassCheckVO.setTemperature1(entry.getValue().get(1).getTemperature1());
                } else if(null!=entry.getValue().get(1).getTemperature()){
                    childrenClassCheckVO.setTemperature(entry.getValue().get(1).getTemperature());
                    childrenClassCheckVO.setTemperature1(entry.getValue().get(0).getTemperature1());
                }
                newList.add(childrenClassCheckVO);
            }else{
                newList.add(entry.getValue().get(0));
            }
        });
        for (ChildrenClassCheckVO childrenClassCheckVO : newList) {
            //设置入园考勤
            String checkInTime = childrenClassCheckVO.getCheckInTime();
            String statusName = "";
            switch (childrenClassCheckVO.getStatus()){
                case 0:statusName="缺勤";break;
                case 1:
                case 2:
                    if(null!=checkInTime && ""!=checkInTime){
                        statusName="入园";
                    }
                    break;
                case 3:statusName="拒接入园";break;
                case 4:statusName="请假";break;
            }
            childrenClassCheckVO.setCheckInTimeCopy(checkInTime);
            if(null!=checkInTime && ""!=checkInTime){
                childrenClassCheckVO.setCheckInTime(checkInTime + "  " + statusName);
            }else{
                childrenClassCheckVO.setCheckInTime(statusName);
            }

            //设置出园考勤
            String checkOutTime = childrenClassCheckVO.getCheckOutTime();
            String statusName2 = "";
            switch (childrenClassCheckVO.getStatus()){
                case 0:statusName2="缺勤";break;
                case 1:
                case 2:
                    if(null!=checkOutTime && ""!=checkOutTime){
                        statusName2="出园";
                    }
                    break;
                case 3:statusName2="拒接入园";break;
                case 4:statusName2="请假";break;
            }
            childrenClassCheckVO.setCheckOutTimeCopy(checkOutTime);
            if(null!=checkOutTime && ""!=checkOutTime){
                childrenClassCheckVO.setCheckOutTime(checkOutTime + "  " + statusName2);
            }else{
                childrenClassCheckVO.setCheckOutTime(statusName2);
            }
        }

        PaginateInMemory paginateInMemory = new PaginateInMemory();
        return paginateInMemory.page(newList, PageRequest.of(query.getPageNum(), query.getPageSize()));
    }

    /**
     * 编辑宝宝入园、离园时间
     * @param childrenClassCheckVO
     */
    @Override
    public void editChildrenCheckTime(ChildrenClassCheckVO childrenClassCheckVO) {
        Assert.notNull(childrenClassCheckVO.getChildrenId(),"childrenId不能为空");
        Assert.notNull(childrenClassCheckVO.getCheckInTime(),"checkInTime不能为空");
        Assert.notNull(childrenClassCheckVO.getCheckOutTime(),"checkOutTime不能为空");
        Assert.notNull(childrenClassCheckVO.getCheckInTimeCopy(),"checkInTimeCopy不能为空");
        Assert.notNull(childrenClassCheckVO.getCheckOutTimeCopy(),"checkOutTimeCopy不能为空");

        // 3. 获取启用的考勤规则（无规则则不处理）
        CheckInRule rule = checkInRulerRepository.findByEnableStatusAndAreaIdAndDel_flag(1, childrenClassCheckVO.getAreaId(),"0");
        Integer statusIn = null;
        Integer statusOut = null;
        if (null != rule) {
            // 定义格式，精确匹配 "yyyy-MM-dd HH:mm:ss"
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            //判断入园时间
            boolean inCheckInTimeRange = cCheckerService.isInCheckInTimeRange(LocalDateTime.parse(childrenClassCheckVO.getCheckInTimeCopy(),formatter), rule);
            if(inCheckInTimeRange){
                //入园
                statusIn = 1;
            }else{
                //迟到
                statusIn = 5;
            }
            //判断离园时间
            boolean inCheckOutTimeRange = cCheckerService.isInCheckOutTimeRange(LocalDateTime.parse(childrenClassCheckVO.getCheckOutTimeCopy(),formatter), rule);
            if(inCheckOutTimeRange){
                //离园
                statusOut = 2;
            }else {
                //早退
                statusOut = 6;
            }
        }
        //修改入园时间
        int i = classesRepository.updateCheckInTime(childrenClassCheckVO.getCheckInTimeCopy(), statusIn, childrenClassCheckVO.getCheckInTime(), childrenClassCheckVO.getChildrenId());
        //修改离园时间
        int j = classesRepository.updateCheckOutTime(childrenClassCheckVO.getCheckOutTimeCopy(), statusOut, childrenClassCheckVO.getCheckOutTime(), childrenClassCheckVO.getChildrenId());
    }

}
